<?php
/**
 * @package	minBot
 * @author	Martin Sadový <sodae@email.cz>
 * @copyright   2009 Martin Sadový
 */


require_once dirname(__FILE__).'/XMPPHP/XMPP.php';
require_once dirname(__FILE__).'/Nette/Object.php';
require_once dirname(__FILE__).'/dibi/dibi.php';
require_once dirname(__FILE__).'/Message.php';
require_once dirname(__FILE__).'/Plugin.php';
require_once dirname(__FILE__).'/Auth.php';

class minBotException extends XMPPHP_Exception
{}

class minBot extends Object
{

    /**
     * Return time connect to server
     * @var int UNIXTIME
     */
    public $startTime   = 0;

    /**
     * Plugin list
     * @var array
     */
    protected $plugins    = array();

    /**
     * Name a room
     * @var string
     */
    protected $room;

    /**
     * Nick in room
     * @var string
     */
    protected $nick = 'minBot';

    /**
     * Return connection with jabber server
     * @var XMP_PHP
     */
    protected $connection;

    /**
     * Will be restart (reconnect) ?
     * @var bool
     */
    public $needRestart = false;


    /**
     * Get connection instance XMPPHP_XMPP
     * @return XMPPHP_XMPP
     */
    public function getConnection()
    {
        return $this->connection;
    }

    /**
     * Return room address
     * @return string
     */
    public function getRoom()
    {
        return $this->room;
    }

    /**
     * Return nick in room
     * @return string
     */
    public function getRoomNick()
    {
        return $this->nick;
    }

    /**
     * Registration plugin
     * @param string $name Name plugin
     */
    public function registerPlugin($name)
    {
        if(!isset($this->plugins[$name])){
            $code = file_get_contents(dirname(__FILE__).'/Plugins/'.$name.'.php');
            
            $class = "Plugin_".md5(microtime().$name.rand(0,9999999) )."_".$name;
            $tempFile = dirname(__FILE__).'/temp/'.$class.'.temp.php';
            $code = preg_replace("#class ([0-9A-Za-z_]{1,})Plugin#", "class ".$class, $code);
            file_put_contents($tempFile, $code);
            
            require_once $tempFile;
            $this->plugins[$name] = new $class($this);
            return true;
        }

        throw new minBotException('Plugin "'.$name.'" is ready !');
    }
    
    /**
     * Login to jabber server
     * @param string $hostname Server
     * @param int $port Port
     * @param string $username Username
     * @param string $password Password
     * @param string $resource Resource for connect
     */                
    public function connect($hostname, $port, $username, $password, $resource = 'minBot')
    { 
        $conn = new XMPPHP_XMPP($hostname, $port, $username, $password, $resource);
        $conn->connect();
        $conn->processUntil('session_start');
        $conn->presence();
        
        $this->connection = $conn;
        $this->startTime = time();
    }

    /**
     * Login to room
     * @param string $room
     * @param string $nick
     */          
    public function loginToRoom($room, $nick = null)
    {
        $this->nick = is_null($nick)?$this->nick:$nick;
        $this->room = $room;

        $this->connection
             ->presence(null,
                        'available',
                        $this->room.'/'.$this->nick
                    );
    }
    
    /**
     * Run
     */        
    public function run()
    {
        while(!$this->connection->isDisconnected()) {
            $payloads = $this->connection->processUntil(array('message', 'presence', 'end_stream', 'session_start'));
            foreach($payloads as $event) {
                $this->onEventCallPlugin($event);
            }
        }
    }

    /**
     * Skip old messages
     */         
    public function deadLastMessages()
    {
        while(true) {
            $payloads = $this->connection->processUntil(array('message', 'presence'));
            foreach($payloads as $event) {
                if($event[0] == 'message'){
                    $data = new Message($event[1]);
                    if(is_null($data->getTime(true))){
                        $this->onEventCallPlugin($event);
                        return;
                    }
                }else{
                    $this->onEventCallPlugin($event);
                }
            }
            
        }
    }
    
    /**
     * Event
     */         
    private function onEventCallPlugin($event)
    {
        foreach($this->plugins as $plugin){
            if($event[1]['from'] != $this->room."/".$this->nick){
                if( is_callable($plugin->onMessage) AND ($event[0] == 'message') ){
                    if( !is_null($event[1]['body']) ){
                        if( !isset($message) )
                            $message = new Message($event[1]);

                            call_user_func($plugin->onMessage, $message);
                    }

                }elseif(is_callable($plugin->onEvent)){
                    call_user_func($plugin->onEvent, $event[0], $event[1]);

                }
            }
            flush();
        }
    }

    /**
     * Send Message
     * @param string $message
     * @param string $recipient 
     */                   
    public function sendMessage($message, $recipient = null)
    {
        if(is_null($recipient) AND !empty($this->room) ){
            $recipient = $this->room;
            $type = 'groupchat';
        }else{
            $type = 'chat';
        }

        $this->connection->message($recipient, $message, $type);
    }
    
    /**
     * Disconnect
     */         
    public function disconnect()
    {
        $this->connection->disconnect();
    }
    
    /**
     * Shutdown bot
     * @param bool $exception With exception
     */          
    public function shutdown($exception = true)
    {

        foreach($this->plugins as $plugin){
            if(is_callable($plugin->onShutdown)){
                call_user_func($plugin->onShutdown);
            }
        }
        if(!empty($this->room) ){
            $this->connection
                 ->presence(NULL,
                           'unavailable',
                           $this->room.'/'.$this->nick
                       );
        }
        
        if(!$this->connection->isDisconnected()){
            $this->disconnect();
        }
        if($exception)
            throw new minBotException('Shutdown Bot');
    }
    
    /**
     *  Restart bot
     */         
    public function restart()
    {
        $this->shutdown(false);
        $this->needRestart = true;
        throw new minBotException('Restart Bot');
    }

}
?>